package net.studou.bean.tools;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import net.studou.annotation.IConvertAnnotation;
import net.studou.convert.BasicConvert;
import net.studou.exception.SystemException;
import net.studou.po.User;
import net.studou.vo.VUser;

public class BeanUtils {

	@SuppressWarnings("unchecked")
	public static void copyList(List source, List target, Properties properties) {
		try {
			for (Object sourceObg : source) {
				Object targetObj = sourceObg.getClass().newInstance();
				BeanUtils.copyBean(sourceObg, targetObj, properties);
				target.add(targetObj);
			}
		} catch (Exception e) {
			throw new SystemException("System error");
		}
	}

	public static void copyBean(Object source, Object target, Properties properties) {
		BeanUtils.createIConvert(target, properties);

		Map<String, IConvert> propertyMap = properties.getPropertyMap();
		String logKey = null;
		try {
			for (String key : propertyMap.keySet()) {
				logKey = key;

				String[] tPros = BeanUtils.splitProperty(key.substring(key.indexOf(":") + 1));
				Object object = target;
				for (int i = 0; i < tPros.length; i++) {
					Field tField = object.getClass().getDeclaredField(tPros[i]);
					tField.setAccessible(true);
					if (i < tPros.length - 1) {
						Object targetProperty = tField.get(object);
						if (targetProperty == null) {
							targetProperty = tField.getType().newInstance();
						}
						tField.set(object, targetProperty);
						object = targetProperty;
					} else {
						String[] sPros = BeanUtils.splitProperty(key.substring(0, key.indexOf(":")));
						for (int j = 0; j < sPros.length; j++) {
							Field sField = source.getClass().getDeclaredField(sPros[j]);
							sField.setAccessible(true);
							if (j < sPros.length - 1) {
								source = sField.get(source);
							} else {
								tField.set(object, propertyMap.get(key).convert(sField.get(source)));
							}
						}
					}
				}
			}
		} catch (Exception e) {
			throw new SystemException("Copy bean error " + source + " to " + target + "--" + logKey, e);
		}
	}

	private static String[] splitProperty(String tProperty) {
		String[] pros = tProperty.split("\\.");
		return pros;
	}

	private static void createIConvert(Object target, Properties properties) {
		Map<String, IConvert> map = properties.getPropertyMap();
		Field[] fields = target.getClass().getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(IConvertAnnotation.class)) {
				IConvertAnnotation convertAnnotation = field.getAnnotation(IConvertAnnotation.class);
				String key = convertAnnotation.key();
				String param = convertAnnotation.param();
				String convertClassName = convertAnnotation.convertClassName();
				IConvert convert = map.get(key);
				if (convert instanceof BasicConvert) {
					map.put(key, BeanUtils.initConvert(convertClassName, param));
				}
			}
		}
	}

	private static IConvert initConvert(String convertClassName, String param) {
		IConvert convert = null;
		try {
			Class<?> clazz = Class.forName("net.studou.convert." + convertClassName);
			if ("".equals(param)) {
				convert = (IConvert) clazz.newInstance();
			} else {
				Constructor<?> constructor = clazz.getConstructor(Integer.class);
				convert = (IConvert) constructor.newInstance(Integer.parseInt(param));
			}
		} catch (Exception e) {
			throw new SystemException("System error");
		}
		return convert;
	}

	public static void main(String[] args) {
		VUser u = new VUser();
		u.setPassword("sss");

		User uu = new User();
		User p = new User();
		p.setUserName("ppp");
		uu.setParentUser(p);

		try {
			Properties pp = new Properties("password", "password");
			BeanUtils.copyBean(u, uu, pp);
			System.out.println(uu.getPassword());
		} catch (SystemException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
